"""
资源规划应用程序主类

封装整个应用程序的业务逻辑，提供完整的流程管理：
- 数据加载和验证
- 资源规划计算
- 结果输出和报告生成
- 进度跟踪和日志记录
"""

import logging
import sys
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Optional, Tuple
import yaml

import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

try:
    from services.data_loader import DataLoader
    from services.resource_planner import ResourcePlanner, AllocationStrategy
    from models.project import Project
    from models.resource import Resource
    from models.task import Task
except ImportError as e:
    print(f"导入错误：{e}")
    print("请确保所有模块都在正确的路径下")
    sys.exit(1)


class ResourcePlanApp:
    """资源规划应用程序主类"""
    
    def __init__(self, config_path: str = None, debug: bool = False):
        """
        初始化应用程序
        
        Args:
            config_path: 配置文件路径
            debug: 是否启用调试模式
        """
        self.config_path = config_path or "config.yaml"
        self.debug = debug
        self.config = {}
        self.logger = None
        
        # 业务对象
        self.data_loader = None
        self.planner = None
        
        # 数据
        self.projects: List[Project] = []
        self.resources: List[Resource] = []
        self.tasks: List[Task] = []
        
        # 结果
        self.planning_result = None
        
        self._setup_application()
    
    def _setup_application(self):
        """初始化应用程序配置"""
        try:
            self._load_config()
            self._setup_logging()
            self._initialize_services()
            
            self.logger.info("应用程序初始化完成")
            
        except Exception as e:
            print(f"应用程序初始化失败：{e}")
            if self.debug:
                import traceback
                traceback.print_exc()
            sys.exit(1)
    
    def _load_config(self):
        """加载配置文件"""
        config_file = Path(self.config_path)
        if not config_file.exists():
            raise FileNotFoundError(f"配置文件不存在：{self.config_path}")
        
        try:
            with open(config_file, 'r', encoding='utf-8') as f:
                self.config = yaml.safe_load(f)
            print(f"配置文件加载成功：{self.config_path}")
        except Exception as e:
            raise Exception(f"配置文件解析失败：{e}")
    
    def _setup_logging(self):
        """设置日志配置"""
        log_config = self.config.get("logging", {})
        log_level = "DEBUG" if self.debug else log_config.get("level", "INFO")
        log_file = log_config.get("file")
        
        # 设置日志格式
        log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
        
        # 设置处理器
        handlers = [logging.StreamHandler(sys.stdout)]
        if log_file:
            log_dir = Path(log_file).parent
            log_dir.mkdir(parents=True, exist_ok=True)
            handlers.append(logging.FileHandler(log_file, encoding='utf-8'))
        
        # 配置根日志器
        logging.basicConfig(
            level=getattr(logging, log_level.upper()),
            format=log_format,
            handlers=handlers,
            force=True
        )
        
        self.logger = logging.getLogger(__name__)
        self.logger.info(f"日志系统初始化完成，级别：{log_level}")
    
    def _initialize_services(self):
        """初始化业务服务"""
        self.data_loader = DataLoader()
        
        # 确定分配策略
        strategy_config = self.config.get("algorithm", {}).get("allocation_strategy", {})
        strategy_name = strategy_config.get("default", "skill_first")
        
        if strategy_name == "skill_first":
            strategy = AllocationStrategy.SKILL_FIRST
        elif strategy_name == "workload_first":
            strategy = AllocationStrategy.WORKLOAD_FIRST
        else:
            strategy = AllocationStrategy.PRIORITY_FIRST
        
        self.planner = ResourcePlanner(strategy)
        
        self.logger.info(f"业务服务初始化完成，使用策略：{strategy_name}")
    
    def load_data(self, projects_file: str = None, resources_file: str = None, tasks_file: str = None) -> bool:
        """
        加载输入数据
        
        Args:
            projects_file: 项目数据文件路径（可选，从配置读取）
            resources_file: 资源数据文件路径（可选，从配置读取）
            tasks_file: 任务数据文件路径（可选，从配置读取）
            
        Returns:
            bool: 加载是否成功
        """
        try:
            self.logger.info("开始加载输入数据...")
            
            # 确定数据文件路径
            data_sources = self.config.get("data_sources", {})
            projects_file = projects_file or data_sources.get("projects_file")
            resources_file = resources_file or data_sources.get("resources_file")
            tasks_file = tasks_file or data_sources.get("tasks_file")
            
            if not all([projects_file, resources_file, tasks_file]):
                raise ValueError("数据文件路径未完整配置")
            
            # 检查文件是否存在
            for file_path, file_type in [(projects_file, "项目"), (resources_file, "资源"), (tasks_file, "任务")]:
                if not Path(file_path).exists():
                    raise FileNotFoundError(f"{file_type}数据文件不存在：{file_path}")
            
            # 加载数据
            data = self.data_loader.load_all_data(projects_file, resources_file, tasks_file)
            
            self.projects = data['projects']
            self.resources = data['resources']
            self.tasks = data['tasks']
            
            # 打印加载统计
            self.logger.info(f"数据加载完成：")
            self.logger.info(f"  - 项目数量：{len(self.projects)}")
            self.logger.info(f"  - 资源数量：{len(self.resources)}")
            self.logger.info(f"  - 任务数量：{len(self.tasks)}")
            
            return True
            
        except Exception as e:
            self.logger.error(f"数据加载失败：{e}")
            if self.debug:
                import traceback
                traceback.print_exc()
            return False
    
    def validate_data(self) -> Tuple[bool, List[str]]:
        """
        验证数据完整性和合理性
        
        Returns:
            Tuple[bool, List[str]]: (验证是否通过, 问题列表)
        """
        self.logger.info("开始数据验证...")
        
        issues = []
        
        try:
            # 基本数量检查
            if not self.projects:
                issues.append("未找到项目数据")
            if not self.resources:
                issues.append("未找到资源数据")
            if not self.tasks:
                issues.append("未找到任务数据")
            
            if issues:
                return False, issues
            
            # 项目和任务关联性检查
            project_ids = {p.project_id for p in self.projects}
            task_project_ids = {t.project_id for t in self.tasks}
            
            orphan_tasks = task_project_ids - project_ids
            if orphan_tasks:
                issues.append(f"存在孤立任务，所属项目不存在：{orphan_tasks}")
            
            # 资源技能检查
            all_required_skills = set()
            for task in self.tasks:
                if task.required_skills:
                    all_required_skills.update(task.required_skills)
            
            all_available_skills = set()
            for resource in self.resources:
                if resource.skills:
                    all_available_skills.update(resource.skills.keys())
            
            missing_skills = all_required_skills - all_available_skills
            if missing_skills:
                issues.append(f"存在无法满足的技能需求：{missing_skills}")
            
            # 时间合理性检查
            for task in self.tasks:
                if task.start_date and task.end_date and task.start_date > task.end_date:
                    issues.append(f"任务时间不合理 {task.task_id}：开始时间晚于结束时间")
            
            for project in self.projects:
                if project.start_date and project.end_date and project.start_date > project.end_date:
                    issues.append(f"项目时间不合理 {project.project_id}：开始时间晚于结束时间")
            
            # 工作量合理性检查
            for task in self.tasks:
                if task.estimated_hours and task.estimated_hours <= 0:
                    issues.append(f"任务工作量不合理 {task.task_id}：{task.estimated_hours}小时")
            
            validation_passed = len(issues) == 0
            
            if validation_passed:
                self.logger.info("数据验证通过")
            else:
                self.logger.warning(f"数据验证发现{len(issues)}个问题")
                for issue in issues:
                    self.logger.warning(f"  - {issue}")
            
            return validation_passed, issues
            
        except Exception as e:
            self.logger.error(f"数据验证过程中发生错误：{e}")
            return False, [f"验证过程错误：{e}"]
    
    def execute_planning(self) -> bool:
        """
        执行资源规划计算
        
        Returns:
            bool: 规划是否成功完成
        """
        try:
            self.logger.info("开始执行资源规划...")
            
            if not all([self.projects, self.resources, self.tasks]):
                raise ValueError("数据未加载，无法执行规划")
            
            # 执行规划
            self.planning_result = self.planner.plan_resources(
                self.projects, self.resources, self.tasks
            )
            
            # 记录规划结果
            if self.planning_result.success:
                self.logger.info("资源规划成功完成！")
            else:
                self.logger.warning("资源规划完成，但存在问题")
            
            self._log_planning_statistics()
            
            return True
            
        except Exception as e:
            self.logger.error(f"资源规划执行失败：{e}")
            if self.debug:
                import traceback
                traceback.print_exc()
            return False
    
    def _log_planning_statistics(self):
        """记录规划统计信息"""
        if not self.planning_result:
            return
        
        result = self.planning_result
        
        self.logger.info("=== 规划结果统计 ===")
        self.logger.info(f"成功分配任务数：{len(result.allocations)}")
        self.logger.info(f"未分配任务数：{len(result.unassigned_tasks)}")
        self.logger.info(f"资源冲突数：{len(result.conflicts)}")
        self.logger.info(f"警告数量：{len(result.warnings)}")
        
        # 资源利用率统计
        if result.resource_utilization:
            avg_utilization = sum(result.resource_utilization.values()) / len(result.resource_utilization)
            max_utilization = max(result.resource_utilization.values())
            min_utilization = min(result.resource_utilization.values())
            
            self.logger.info(f"资源利用率 - 平均：{avg_utilization:.1%}，最高：{max_utilization:.1%}，最低：{min_utilization:.1%}")
    
    def generate_output(self, output_dir: str = None, verbose: bool = False) -> bool:
        """
        生成输出文件和报告
        
        Args:
            output_dir: 输出目录（可选，从配置读取）
            verbose: 是否输出详细信息
            
        Returns:
            bool: 输出是否成功
        """
        try:
            if not self.planning_result:
                raise ValueError("未执行规划，无法生成输出")
            
            self.logger.info("开始生成输出文件...")
            
            # 确定输出目录
            output_config = self.config.get("output", {})
            output_dir = output_dir or output_config.get("directory", "output")
            output_path = Path(output_dir)
            output_path.mkdir(parents=True, exist_ok=True)
            
            # 生成文件名
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename_pattern = output_config.get("filename_pattern", "resource_plan_{date}_v{version}.xlsx")
            output_filename = filename_pattern.format(
                date=datetime.now().strftime("%Y%m%d"),
                version="01"
            )
            
            output_file = output_path / output_filename
            
            # 这里暂时输出文本格式的规划结果，Excel生成功能待实现
            self._generate_text_report(output_file.with_suffix('.txt'))
            
            # 在控制台显示详细信息
            if verbose:
                self._display_detailed_results()
            
            self.logger.info(f"输出文件生成完成：{output_file}")
            return True
            
        except Exception as e:
            self.logger.error(f"输出生成失败：{e}")
            if self.debug:
                import traceback
                traceback.print_exc()
            return False
    
    def _generate_text_report(self, output_file: Path):
        """生成文本格式的规划报告"""
        result = self.planning_result
        
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write("资源规划结果报告\n")
            f.write("=" * 50 + "\n\n")
            
            # 基本统计
            f.write("基本统计信息：\n")
            f.write(f"  规划状态：{'成功' if result.success else '存在问题'}\n")
            f.write(f"  成功分配任务：{len(result.allocations)}\n")
            f.write(f"  未分配任务：{len(result.unassigned_tasks)}\n")
            f.write(f"  资源冲突：{len(result.conflicts)}\n")
            f.write(f"  警告信息：{len(result.warnings)}\n\n")
            
            # 资源利用率
            if result.resource_utilization:
                f.write("资源利用率：\n")
                for resource_id, utilization in result.resource_utilization.items():
                    f.write(f"  {resource_id}: {utilization:.1%}\n")
                f.write("\n")
            
            # 任务分配详情
            if result.allocations:
                f.write("任务分配详情：\n")
                for allocation in result.allocations:
                    f.write(f"  任务 {allocation.task_id} -> 资源 {allocation.resource_id}\n")
                    f.write(f"    时间：{allocation.start_date} 至 {allocation.end_date}\n")
                    f.write(f"    工作量：{allocation.allocated_hours}小时\n\n")
            
            # 未分配任务
            if result.unassigned_tasks:
                f.write("未分配任务：\n")
                for task_id in result.unassigned_tasks:
                    f.write(f"  - {task_id}\n")
                f.write("\n")
            
            # 冲突信息
            if result.conflicts:
                f.write("资源冲突：\n")
                for conflict in result.conflicts:
                    f.write(f"  资源 {conflict.resource_id} 在 {conflict.date}\n")
                    f.write(f"    需要：{conflict.total_required_hours}小时\n")
                    f.write(f"    可用：{conflict.available_hours}小时\n")
                    f.write(f"    严重程度：{conflict.severity}\n\n")
            
            # 警告信息
            if result.warnings:
                f.write("警告信息：\n")
                for warning in result.warnings:
                    f.write(f"  - {warning}\n")
    
    def _display_detailed_results(self):
        """在控制台显示详细结果"""
        result = self.planning_result
        
        print("\n" + "=" * 60)
        print("详细规划结果")
        print("=" * 60)
        
        # 资源利用率
        if result.resource_utilization:
            print("\n【资源利用率】")
            for resource_id, utilization in sorted(result.resource_utilization.items()):
                status = "正常" if utilization <= 1.0 else "超负荷"
                print(f"  {resource_id:15} {utilization:6.1%} ({status})")
        
        # 未分配任务
        if result.unassigned_tasks:
            print(f"\n【未分配任务 ({len(result.unassigned_tasks)}个)】")
            for task_id in result.unassigned_tasks:
                print(f"  - {task_id}")
        
        # 资源冲突
        if result.conflicts:
            print(f"\n【资源冲突 ({len(result.conflicts)}个)】")
            for conflict in result.conflicts:
                print(f"  {conflict.resource_id} 在 {conflict.date}:")
                print(f"    需要 {conflict.total_required_hours}h，可用 {conflict.available_hours}h")
                print(f"    严重程度：{conflict.severity}")
        
        # 警告信息
        if result.warnings:
            print(f"\n【警告信息 ({len(result.warnings)}个)】")
            for warning in result.warnings:
                print(f"  - {warning}")
        
        print("\n" + "=" * 60)
    
    def run_complete_workflow(self, 
                            projects_file: str = None, 
                            resources_file: str = None, 
                            tasks_file: str = None,
                            output_dir: str = None,
                            verbose: bool = False) -> bool:
        """
        执行完整的工作流程
        
        Args:
            projects_file: 项目数据文件路径
            resources_file: 资源数据文件路径
            tasks_file: 任务数据文件路径
            output_dir: 输出目录
            verbose: 是否详细输出
            
        Returns:
            bool: 整个流程是否成功
        """
        self.logger.info("开始执行完整的资源规划工作流程")
        
        try:
            # 1. 数据加载
            if not self.load_data(projects_file, resources_file, tasks_file):
                return False
            
            # 2. 数据验证
            valid, issues = self.validate_data()
            if not valid:
                self.logger.error("数据验证失败，无法继续：")
                for issue in issues:
                    self.logger.error(f"  - {issue}")
                return False
            
            # 3. 执行规划
            if not self.execute_planning():
                return False
            
            # 4. 生成输出
            if not self.generate_output(output_dir, verbose):
                return False
            
            self.logger.info("完整工作流程执行成功！")
            return True
            
        except Exception as e:
            self.logger.error(f"工作流程执行失败：{e}")
            if self.debug:
                import traceback
                traceback.print_exc()
            return False
    
    def get_summary(self) -> Dict:
        """
        获取应用程序运行摘要
        
        Returns:
            Dict: 摘要信息
        """
        summary = {
            "config_loaded": bool(self.config),
            "data_loaded": bool(self.projects and self.resources and self.tasks),
            "planning_completed": bool(self.planning_result),
            "data_counts": {
                "projects": len(self.projects),
                "resources": len(self.resources),
                "tasks": len(self.tasks)
            }
        }
        
        if self.planning_result:
            summary["planning_results"] = {
                "success": self.planning_result.success,
                "allocated_tasks": len(self.planning_result.allocations),
                "unassigned_tasks": len(self.planning_result.unassigned_tasks),
                "conflicts": len(self.planning_result.conflicts),
                "warnings": len(self.planning_result.warnings)
            }
        
        return summary